package cn.jsu.oj.judgment.utils;

import org.apache.commons.io.FileSystemUtils;

import java.io.*;
import java.util.*;

/**
 * @author: suixuexue
 * @date: 2020/11/18 15:45
 * describe:
 *  发现是本地所需要执行的命令，则在本地机器上执行这个命令
 *
 *  /proc文件系统是一个伪文件系统，它只存在内存当中，而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过/proc得到系统的信息，
 *  并可以改变内核的某些参数。由于系统的信息，如进程，是动态改变的，所以用户或应用程序读取/proc目录中的文件时，proc文件系统是动态从系统内核读出所需信息并提交的。
 *  /proc目录中有一些以数字命名的目录，它们是进程目录。系统中当前运行的每一个进程在/proc下都对应一个以进程号为目录名的目录/proc/pid，它们是读取进程信息的接口。
 *  此外，在Linux 2.6.0-test6以上的版本中/proc/pid目录中有一个task目录，/proc/pid/task目录中也有一些以该进程所拥有的线程的线程号命名的目录/proc/pid/task/tid，
 *  它们是读取线程信息的接口。
 *
 */
public class LocalUsedInfo {
    /**
     * 磁盘使用率
     */
    public static double disk(){
        try {
            long total = FileSystemUtils.freeSpaceKb("/home");
            return (double) total / 1024 / 1024;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 真正的磁盘
     */
    public static double realDisk() {
        try {// 起作用的代码其实就下面这一行, 参数是linux中要执行的代码
            Process df = Runtime.getRuntime().exec("df");
            InputStreamReader reader = new InputStreamReader(df.getInputStream());
            BufferedReader buffer = new BufferedReader(reader);
            Map<String, String> map = new HashMap<String, String>();
            try {
                String line = "";
                while (true) {
                    line = buffer.readLine();//一次读取一行内容
                    if (line == null) {//不结束
                        break;
                    }
                    if (line.startsWith("文件")) {
                        continue;
                    }
                    StringTokenizer tokenizer = new StringTokenizer(line);
                    //StringTokenizer(String str) ：构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格("")、制表符(\t)、换行符(\n)、回车符(\r)。
                    List<String> temp = new ArrayList<String>();
                    while (tokenizer.hasMoreElements()) {//用于检查此标准时间是否存在更多元素
                        String value = tokenizer.nextToken();
                        temp.add(value);
                        System.out.print(value+" ");
                    }
                    System.out.println();
                    System.out.println("这是我的测试"+temp.get(1)+" "+temp.get(2));
                    if (map.get("used") != null && map.get("blocks") != null) {
                        long b = Long.parseLong(map.get("blocks").toString());
                        long u = Long.parseLong(map.get("used").toString());

                        long b1 = Long.parseLong(temp.get(1).toString());
                        long u1 = Long.parseLong(temp.get(2).toString());
                        long l1 = b + b1;
                        long l = u + u1;
                        System.out.println("blocks="+l1);
                        System.out.println("used="+l);
                        map.put("blocks", Long.toString(l1));
                        map.put("used", Long.toString(l));
                    } else {
                        map.put("used", temp.get(2));
                        map.put("blocks", temp.get(1));
                    }
                }
                long used = Long.parseLong(map.get("used").toString());
                long blocks = Long.parseLong(map.get("blocks").toString());
                System.out.println("used="+used);
                System.out.println("blocks="+blocks);
                System.out.println("used * 100="+used * 100);
                System.out.println("used * 100 / blocks="+used * 100 / blocks);
                double result =  used * 100 / blocks;
                System.out.println("result="+result);
                return result;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    buffer.close();
                    reader.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 获取linux系统cpu使用率
     */
    public static float cpuUsage() {
        try {
            Map<?, ?> map1 = LocalUsedInfo.cpuinfo();
            Thread.sleep(5 * 1000);
            Map<?, ?> map2 = LocalUsedInfo.cpuinfo();

            long user1 = Long.parseLong(map1.get("user").toString());
            long nice1 = Long.parseLong(map1.get("nice").toString());
            long system1 = Long.parseLong(map1.get("system").toString());
            long idle1 = Long.parseLong(map1.get("idle").toString());
            System.out.println();
            long user2 = Long.parseLong(map2.get("user").toString());
            long nice2 = Long.parseLong(map2.get("nice").toString());
            long system2 = Long.parseLong(map2.get("system").toString());
            long idle2 = Long.parseLong(map2.get("idle").toString());

            long total1 = user1 + system1 + nice1;
            long total2 = user2 + system2 + nice2;
            float total = total2 - total1;

            long totalIdle1 = user1 + nice1 + system1 + idle1;
            long totalIdle2 = user2 + nice2 + system2 + idle2;
            float totalidle = totalIdle2 - totalIdle1;

            float cpusage = (total / totalidle) * 100;
            return  cpusage;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 功能：CPU使用信息
     * user  从系统启动开始累计到当前时刻，用户态的CPU时间（单位：jiffies） ，不包含 nice值为负进程。1jiffies=0.01秒
     * nice  从系统启动开始累计到当前时刻，nice值为负的进程所占用的CPU时间（单位：jiffies）
     * system  从系统启动开始累计到当前时刻，核心时间（单位：jiffies）
     * idle  从系统启动开始累计到当前时刻，除硬盘IO等待时间以外其它等待时间（单位：jiffies）
     * iowait  从系统启动开始累计到当前时刻，硬盘IO等待时间（单位：jiffies） ，
     * irq  从系统启动开始累计到当前时刻，硬中断时间（单位：jiffies）
     * softirq  从系统启动开始累计到当前时刻，软中断时间（单位：jiffies）
     * */
    public static Map<?, ?> cpuinfo() {
        InputStreamReader inputs = null;
        BufferedReader buffer = null;
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            inputs = new InputStreamReader(new FileInputStream("/proc/stat"));//从/proc/stat文件中读取内容
            buffer = new BufferedReader(inputs);
            String line = "";
            while (true) {
                line = buffer.readLine();//一次读取一行内容
                if (line == null) {//不结束
                    break;
                }
                if (line.startsWith("cpu")) {
                    StringTokenizer tokenizer = new StringTokenizer(line);
                    //StringTokenizer(String str) ：构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格("")、制表符(\t)、换行符(\n)、回车符(\r)。
                    List<String> temp = new ArrayList<String>();
                    while (tokenizer.hasMoreElements()) {//用于检查此标准时间是否存在更多元素
                        String value = tokenizer.nextToken();
                        temp.add(value);
                    }
                    map.put("user", temp.get(1));
                    map.put("nice", temp.get(2));
                    map.put("system", temp.get(3));
                    map.put("idle", temp.get(4));
                    map.put("iowait", temp.get(5));
                    map.put("irq", temp.get(6));
                    map.put("softirq", temp.get(7));
                    map.put("stealstolen", temp.get(8));
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                buffer.close();
                inputs.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return map;
    }

    /**
     * 功能：内存使用率
     * */
    public static double memoryUsage() {
        Map<String, Object> map = new HashMap<String, Object>();
        InputStreamReader inputs = null;
        BufferedReader buffer = null;
        try {
            inputs = new InputStreamReader(new FileInputStream("/proc/meminfo"));
            buffer = new BufferedReader(inputs);
            String line = "";
            while (true) {
                line = buffer.readLine();
                if (line == null)
                    break;
                int beginIndex = 0;
                int endIndex = line.indexOf(":");
                if (endIndex != -1) {
                    String key = line.substring(beginIndex, endIndex);//截取K
                    beginIndex = endIndex + 1;//保证没有:
                    endIndex = line.length();
                    String memory = line.substring(beginIndex, endIndex);//截取V
                    String value = memory.replace("kB", "").trim();
                    map.put(key, value);
                }
            }

            long memTotal = Long.parseLong(map.get("MemTotal").toString());
            long memFree = Long.parseLong(map.get("MemFree").toString());
            long memused = memTotal - memFree;
            long buffers = Long.parseLong(map.get("Buffers").toString());
            long cached = Long.parseLong(map.get("Cached").toString());

            double usage = (double) (memused - buffers - cached) / memTotal * 100;
            return  usage;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                buffer.close();
                inputs.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return 0;
    }

    /**
     * io使用率
     */
    public static float ioUsage(){
        float ioUsage = 0.0f;
        Process pro = null;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "iostat -d -x";
            pro = r.exec(command);
            BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;
            int count =  0;
            while((line=in.readLine()) != null){
                if(++count >= 4){
                    String[] temp = line.split("\\s+");
                    if(temp.length > 1){
                        float util =  Float.parseFloat(temp[temp.length-1]);
                        ioUsage = (ioUsage>util)?ioUsage:util;
                    }
                }
            }
            if(ioUsage > 0){
                ioUsage /= 100;
            }
            in.close();
            pro.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
        }
        return ioUsage;
    }
}
